﻿/******************************************************************************
 * 
 * Announce: CSharpKit, Basic algorithms, components and definitions.
 *           Copyright (C) ShenYongchen.
 *           All rights reserved.
 *   Author: 申永辰.郑州 (shenyczz@163.com)
 *  WebSite: http://github.com/shenyczz/CSharpKit
 *
 * THIS CODE IS LICENSED UNDER THE MIT LICENSE (MIT).
 * THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 
 * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
 * IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
 * PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
 * 
******************************************************************************/

using System;
using System.Numerics;

namespace CSharpKit.Numerics.LinearAlgebra.Factorization
{
    /// <summary>
    /// EVD - 特征值分解 <br/>
    /// </summary>
    /// <remarks>
    /// 假设向量v是方阵A的特征向量，可以一定表示成： Av = λv <br/>
    /// 这里 lambda 表示特征向量v所对应的特征值，并且一个矩阵的一组特征向量是一组正交向量。<br/>
    /// 特征值分解是将一个矩阵分解为： A = QΣQ^T, 其中Q是这个矩阵A的特征向量组成的矩阵，sigma是
    /// 一个对角矩阵，每个对角线上的元素就是一个特征值。特征值分解是一个提取矩阵特征很不错的方法，
    /// 但是它只适合于方阵。
    /// </remarks>
    /// <typeparam name="T"></typeparam>
    public abstract class Evd<T> : ISolver<T>
        where T : struct, IFormattable, IEquatable<T>
    {
        /// <summary>
        /// EVD
        /// </summary>
        /// <param name="eigenVectors">特征向量</param>
        /// <param name="eigenValues">特征向量对应的特征值</param>
        /// <param name="blockDiagonal">对角矩阵</param>
        /// <param name="isSymmetric">对称阵</param>
        protected Evd(Matrix<T> eigenVectors,
            Vector<Complex> eigenValues,
            Matrix<T> blockDiagonal,
            bool isSymmetric)
        {
            EigenVectors = eigenVectors;
            EigenValues = eigenValues;
            D = blockDiagonal;
            IsSymmetric = isSymmetric;
        }


        /// <summary>
        /// 是否对称阵
        /// </summary>
        public bool IsSymmetric { get; private set; }

        /// <summary>
        /// Gets or sets eigenvectors（特征向量）.
        /// </summary>
        public Matrix<T> EigenVectors { get; private set; }

        /// <summary>
        /// 特征向量对应的特征值(λ),升序
        /// Gets or sets the eigen values (λ) of matrix in ascending value.
        /// </summary>
        public Vector<Complex> EigenValues { get; private set; }

        /// <summary>
        /// 块对角线特征值矩阵
        /// Gets or sets the block diagonal eigenvalue matrix.
        /// </summary>
        public Matrix<T> D { get; private set; }


        /// <summary>
        /// 方阵行列式的绝对值?
        /// Gets the absolute value of determinant of the square matrix for which the EVD was computed.
        /// </summary>
        public abstract T Determinant { get; }

        /// <summary>
        /// 有效的数值矩阵秩。
        /// Gets the effective numerical matrix rank.
        /// </summary>
        /// <value>
        /// The number of non-negligible singular values（奇异值）.
        /// </value>
        public abstract int Rank { get; }

        /// <summary>
        /// 矩阵是否为满秩
        /// </summary>
        /// <value>
        /// <c>true</c>:  if the matrix is full rank. <br/>
        /// <c>false</c>: otherwise .</value> <br/>
        public abstract bool IsFullRank { get; }



        #region ISolver<T>

        public Matrix<T> Solve(Matrix<T> input)
        {
            var x = Matrix<T>.Builder.SameAs(EigenVectors, EigenVectors.ColumnCount, input.ColumnCount, fullyMutable: true);
            Solve(input, x);
            return x;
        }
        public abstract void Solve(Matrix<T> input, Matrix<T> result);

        public Vector<T> Solve(Vector<T> input)
        {
            var x = Vector<T>.Builder.SameAs(EigenVectors, EigenVectors.ColumnCount);
            Solve(input, x);
            return x;
        }
        public abstract void Solve(Vector<T> input, Vector<T> result);

        #endregion


        //}}@@@
    }


}

